#include "S5.h"
#include "systick.h"


i2c_addr_def s5_init(uint8_t address)
{
    i2c_addr_def result;
    uint8_t i;

    for (i = 0; i < 4; ++i)
    {
        result = get_board_address(address + 2 * i);
        if (result.flag == 1)
        {
            ms253_init(result.periph, result.addr);
        }
    }

    return result;
}

void ms253_init(uint32_t periph, uint8_t slave_address)
{
    // ms253软复位
    i2c_delay_byte_write(periph, slave_address, CommandReg, RESET_COMMAND);
    i2c_delay(2000);

    i2c_delay_byte_write(periph, slave_address, ModeReg, 0x3D);

    // 计数器重载值0x30
    i2c_delay_byte_write(periph, slave_address, TReloadRegH, 0x00);
    i2c_delay_byte_write(periph, slave_address, TReloadRegL, 0x30);

    // 计数器受TModeReg寄存器影响，非门控模式，计数器清零后置ComIrqReg寄存器的TimerIRq为1，prescaler为0xD3E
    i2c_delay_byte_write(periph, slave_address, TModeReg, 0x8D);
    i2c_delay_byte_write(periph, slave_address, TPrescalerReg, 0x3E);

    // 对发送进行100%ASK的调制
    i2c_delay_byte_write(periph, slave_address, TxAutoReg, 0x40);

    // 禁止串行UART中MX和DTRQ
    clear_bit_mask(periph, slave_address, TestPinEnReg, 0x80);

    i2c_delay_byte_write(periph, slave_address, TxAutoReg, 0x40);

    clear_bit_mask(periph, slave_address, TxControlReg, 0x03);

    delay_1ms(500);

    set_bit_mask(periph, slave_address, TxControlReg, 0x03);

    // 打开crypto1单元
    i2c_delay_byte_write(periph, slave_address, Status2Reg, 0x08);

    i2c_delay_byte_write(periph, slave_address, ModeReg, 0x3D);

    i2c_delay_byte_write(periph, slave_address, RxSelReg, 0x86);

    // 接收器信号电压增益系数：48dB
    i2c_delay_byte_write(periph, slave_address, RFCfgReg, 0x7F);

    i2c_delay_byte_write(periph, slave_address, TReloadRegL, 30);
    i2c_delay_byte_write(periph, slave_address, TReloadRegH, 0);

    i2c_delay_byte_write(periph, slave_address, TModeReg, 0x8D);
    i2c_delay_byte_write(periph, slave_address, TPrescalerReg, 0x3E);

    delay_1ms(500);

    set_bit_mask(periph, slave_address, TxControlReg, 0x03);
}

void s5_all_init(s5_addr_def *s5_address, uint8_t s5_addr)
{
    uint8_t i;

    for (i = 0; i < 4; ++i)
    {
        s5_address->nfc_addr[i] = get_board_address(s5_addr + i * 2);

        if (s5_address->nfc_addr[i].flag == 1)
            ms253_init(s5_address->nfc_addr[i].periph, s5_address->nfc_addr[i].addr);
    }
}

void set_bit_mask(uint32_t periph, uint8_t slave_address, uint8_t reg_address, uint8_t mask)
{
    uint8_t tmp = 0x00;

    i2c_delay_read(periph, slave_address, reg_address, &tmp, 1);

    i2c_delay_byte_write(periph, slave_address, reg_address, tmp | mask);
}

void clear_bit_mask(uint32_t periph, uint8_t slave_address, uint8_t reg_address, uint8_t mask)
{
    uint8_t tmp = 0x00;

    i2c_delay_read(periph, slave_address, reg_address, &tmp, 1);

    i2c_delay_byte_write(periph, slave_address, reg_address, tmp & ~mask);
}

uint8_t s5_detect(uint32_t periph, uint8_t slave_address, uint8_t *card_num)
{
    uint8_t type[2];

    if(pcd_request(periph, slave_address, 0x52, type) == MI_OK)
    {
        if(pcd_anti_collision(periph, slave_address, card_num) == MI_OK)
        {
            if(pcd_select(periph, slave_address, card_num) == MI_OK)
            {
                return SUCCESS;
            }
        }
    }

    return FAIL;
}

uint8_t pcd_select(uint32_t periph, uint8_t slave_address, uint8_t *snr) {
    uint8_t status;
    uint8_t i;
    uint16_t unLen;
    uint8_t ucComMS523Buf[MAXRLEN];

    ucComMS523Buf[0] = 0x93;
    ucComMS523Buf[1] = 0x70;
    ucComMS523Buf[6] = 0;
    for (i = 0; i < 4; i++)
    {
        ucComMS523Buf[i + 2] = *(snr + i);
        ucComMS523Buf[6]  ^= *(snr + i);
    }
    calculate_CRC(periph, slave_address, ucComMS523Buf, 7, &ucComMS523Buf[7]);

    clear_bit_mask(periph, slave_address, Status2Reg, 0x08);

    status = pcd_commands_523(periph, slave_address, 0x0C,ucComMS523Buf,9,ucComMS523Buf,&unLen);

    if ((status == MI_OK) && (unLen == 0x18))
    {
        status = MI_OK;
    }
    else
    {
        status = MI_ERR;
    }

    return status;
}

void calculate_CRC(uint32_t periph, uint8_t address, uint8_t *in_data, uint8_t len, uint8_t *out_data) {
    uint8_t i,n;

    clear_bit_mask(periph, address, DivIrqReg, 0x04);
    i2c_delay_byte_write(periph, address, CommandReg, 0x00);
    set_bit_mask(periph, address, FIFOLevelReg, 0x80);

    i2c_delay_write(periph, address,FIFODataReg, in_data, len);
    i2c_delay_byte_write(periph, address, CommandReg, 0x03);
    i = 0xFF;
    do
    {
        i2c_delay_read(periph, address, DivIrqReg, &n, 1);
        i--;
    }
    while ((i != 0) && !(n & 0x04));
    i2c_delay_read(periph, address, CRCResultRegL, &out_data[0], 1);
    i2c_delay_read(periph, address, CRCResultRegM, &out_data[1], 1);
}

uint8_t pcd_anti_collision(uint32_t periph, uint8_t slave_address, uint8_t *snr) {
    uint8_t status;
    uint8_t i,snr_check=0;
    uint16_t  unLen;
    uint8_t ucComMS523Buf[MAXRLEN];


    clear_bit_mask(periph, slave_address, Status2Reg, 0x08);
    i2c_delay_byte_write(periph, slave_address, BitFramingReg, 0x00);
    clear_bit_mask(periph, slave_address, CollReg, 0x80);

    ucComMS523Buf[0] = 0x93;
    ucComMS523Buf[1] = 0x20;

    status = pcd_commands_523(periph, slave_address, 0x0C, ucComMS523Buf, 2, ucComMS523Buf, &unLen);

    if (status == MI_OK)
    {
        for (i = 0; i < 4; i++)
        {
            *(snr + i)  = ucComMS523Buf[i];
            snr_check ^= ucComMS523Buf[i];
        }
        if (snr_check != ucComMS523Buf[i])
        {
            status = MI_ERR;
        }
    }

    set_bit_mask(periph,slave_address, CollReg, 0x80);
    return status;
}

uint8_t pcd_request(uint32_t periph, uint8_t slave_address, uint8_t req_code, uint8_t *tag_type) {
    uint8_t status;
    uint16_t  unLen;
    uint8_t ucComMS523Buf[MAXRLEN];

    clear_bit_mask(periph, slave_address, Status2Reg, 0x08);
    i2c_delay_byte_write(periph, slave_address, BitFramingReg, 0x07);
    set_bit_mask(periph, slave_address, TxControlReg, 0x03);

    ucComMS523Buf[0] = req_code;

    status = pcd_commands_523(periph, slave_address, 0x0C, ucComMS523Buf, 1, ucComMS523Buf, &unLen);
    if ((status == MI_OK) && (unLen == 0x10))
    {
        *tag_type = ucComMS523Buf[0];
        *(tag_type + 1) = ucComMS523Buf[1];
    }
    else
    {
        status = MI_ERR;
    }

    return status;
}

uint8_t s5_verify(uint32_t periph, uint8_t slave_address, uint8_t auth_mode, uint8_t len, uint8_t *Key, uint8_t *snr)
{
    uint8_t rt = 2;
    if (len <= 63)
    {
        rt = pcd_auth_state(periph, slave_address, auth_mode, len, Key, snr);
    }
    return rt;
}

uint8_t pcd_auth_state(uint32_t periph, uint8_t slave_address, uint8_t mode, uint8_t len, uint8_t *key, uint8_t *snr) {
    uint8_t status;
    uint16_t  unLen;
    uint8_t i, ucComMS523Buf[MAXRLEN];
    uint8_t tmp;

    ucComMS523Buf[0] = mode;
    ucComMS523Buf[1] = len;
    for (i = 0; i < 6; i++)
    {
        ucComMS523Buf[i + 2] = *(key + i);
    }
    for (i = 0; i < 4; i++)
    {
        ucComMS523Buf[i + 8] = *(snr + i);
    }


    status = pcd_commands_523(periph, slave_address, 0x0E, ucComMS523Buf, 12, ucComMS523Buf, &unLen);
    i2c_delay_read(periph, slave_address, Status2Reg, &tmp, 1);
    if ((status != MI_OK) || (!(tmp & 0x08)))
    {
        status = MI_ERR;
    }

    return status;
}

uint8_t s5_write_data(uint32_t periph, uint8_t slave_address, uint8_t len, uint8_t *data)
{
    uint8_t rt = 2;
    if(len <= 63)
    {
        rt = pcd_write(periph, slave_address, len, data);
    }

    return rt;
}

uint8_t pcd_write(uint32_t periph, uint8_t slave_address, uint8_t len, uint8_t *data) {
    uint8_t status;
    uint16_t  unLen;
    uint8_t i, ucComMS523Buf[MAXRLEN];

    ucComMS523Buf[0] = 0xA0;
    ucComMS523Buf[1] = len;
    calculate_CRC(periph, slave_address, ucComMS523Buf, 2, &ucComMS523Buf[2]);

    status = pcd_commands_523(periph, slave_address,0x0C, ucComMS523Buf, 4, ucComMS523Buf, &unLen);

    if ((status != MI_OK) || (unLen != 4) || ((ucComMS523Buf[0] & 0x0F) != 0x0A))
    {
    status = MI_ERR;
    }

    if (status == MI_OK)
    {
        //memcpy(ucComMS523Buf, pData, 16);
        for (i = 0; i < 16; i++)
        {
            ucComMS523Buf[i] = *(data + i);
        }
        calculate_CRC(periph, slave_address, ucComMS523Buf, 16, &ucComMS523Buf[16]);

        status = pcd_commands_523(periph, slave_address, 0x0C, ucComMS523Buf, 18, ucComMS523Buf, &unLen);
        if ((status != MI_OK) || (unLen != 4) || ((ucComMS523Buf[0] & 0x0F) != 0x0A))
        {
            status = MI_ERR;
        }
    }

    return status;
}

uint8_t pcd_read(uint32_t periph, uint8_t slave_address, uint8_t len, uint8_t *data) {
    uint8_t status;
    uint16_t  unLen;
    uint8_t i,ucComMS523Buf[MAXRLEN];

    ucComMS523Buf[0] = 0x30;
    ucComMS523Buf[1] = len;
    calculate_CRC(periph, slave_address, ucComMS523Buf, 2, &ucComMS523Buf[2]);

    status = pcd_commands_523(periph, slave_address, 0x0C, ucComMS523Buf, 4, ucComMS523Buf, &unLen);
    if ((status == MI_OK) && (unLen == 0x90))
    //   {   memcpy(pData, ucComMS523Buf, 16);   }
    {
        for (i = 0; i < 16; i++)
        {
          *(data + i) = ucComMS523Buf[i];
        }
    }
    else
    {
        status = MI_ERR;
    }

    return status;
}

uint8_t s5_read_data(uint32_t periph, uint8_t slave_address, uint8_t len, uint8_t *data)
{
    uint8_t rt = 2;
    if(len <= 63)
    {
        rt = pcd_read(periph, slave_address, len, data);
    }

    return rt;
}

void s5_sleep(uint32_t periph, uint8_t slave_address)
{
    pcd_halt(periph, slave_address);
}

uint8_t pcd_halt(uint32_t periph, uint8_t address) {
    uint16_t  unLen;
    uint8_t ucComMS523Buf[MAXRLEN];

    ucComMS523Buf[0] = 0x50;
    ucComMS523Buf[1] = 0;
    calculate_CRC(periph, address, ucComMS523Buf, 2, &ucComMS523Buf[2]);

    pcd_commands_523(periph, address, 0x0C, ucComMS523Buf, 4, ucComMS523Buf, &unLen);

    return MI_OK;
}

uint8_t pcd_commands_523(uint32_t i2c_periph,uint8_t i2c_addr,  uint8_t Command, uint8_t *pInData, uint8_t InLenByte, uint8_t *pOutData, uint16_t  *pOutLenBit)
{
    int8_t status = MI_ERR;
    uint8_t irqEn   = 0x00;
    uint8_t waitFor = 0x00;
    uint8_t lastBits;
    uint8_t n;
    uint16_t i;

    switch (Command)
    {
        case 0x0E:
            irqEn = 0x12;
            waitFor = 0x10;
            break;
        case 0x0C:
            irqEn = 0x77;
            waitFor = 0x30;
            break;
        default:
            break;
    }

    i2c_delay_byte_write(i2c_periph, i2c_addr, ComIEnReg, irqEn | 0x80);
    clear_bit_mask(i2c_periph, i2c_addr, ComIrqReg, 0x80);
    i2c_delay_byte_write(i2c_periph, i2c_addr, CommandReg, 0x00);
    set_bit_mask(i2c_periph, i2c_addr, FIFOLevelReg, 0x80);

    i2c_delay_write(i2c_periph, i2c_addr, FIFODataReg, pInData, InLenByte);

    i2c_delay_byte_write(i2c_periph,i2c_addr,CommandReg, Command);

    if (Command == 0x0C)
    {
        set_bit_mask(i2c_periph, i2c_addr, BitFramingReg, 0x80);
    }

    i = 800;
    do
    {
        i2c_delay_read(i2c_periph, i2c_addr, ComIrqReg, &n, 1);
        i--;
    }
    while ((i != 0) && !(n & 0x01) && !(n & waitFor));
    clear_bit_mask(i2c_periph, i2c_addr, BitFramingReg,  0x80);

    if (i != 0)
    {
        i2c_delay_read(i2c_periph, i2c_addr, ErrorReg, &n, 1);
        if (!(n & 0x1B))
        {
            status = MI_OK;
            if (n & irqEn & 0x01)
            {
                status = MI_NOTAGERR;
            }
            if (Command == 0x0C)
            {
                i2c_delay_read(i2c_periph, i2c_addr, FIFOLevelReg, &n, 1);
                i2c_delay_read(i2c_periph, i2c_addr, ControlReg, &lastBits, 1);
                lastBits &= 0x07;
                if (lastBits)
                {
                  *pOutLenBit = (n - 1) * 8 + lastBits;
                }
                else
                {
                  *pOutLenBit = n * 8;
                }
                if (n == 0)
                {
                    n = 1;
                }
                if (n > MAXRLEN)
                {
                    n = MAXRLEN;
                }
                i2c_delay_read(i2c_periph, i2c_addr, FIFODataReg, pOutData, n);
            }
        }
        else
        {
            status = MI_ERR;
        }
    }
    set_bit_mask(i2c_periph, i2c_addr, ControlReg, 0x80);           // stop timer now
    i2c_delay_byte_write(i2c_periph, i2c_addr, CommandReg, 0x00);
    return status;
}
